package com.ynkbny.util;

import cn.hutool.core.util.ObjectUtil;
import com.ynkbny.annotate.*;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * Mongo工具类
 *
 * @author : juzipi123
 * @date : 2023-7-20
 */
@Component
public class MongoUtil {

    @Resource
    private MongoTemplate mongoTemplate;

    /**
     * 添加文章
     *
     * @param data 添加的数据
     * @return 结果
     */
    public <T> int save(T data) {
        mongoTemplate.save(data);
        return 1;
    }

    /**
     * 添加文章
     *
     * @param data 添加的数据
     * @param collectionName 对应的数据库集合名字
     * @return 结果
     */
    public <T> int save(T data, String collectionName) {
        mongoTemplate.save(data, collectionName);
        return 1;
    }

    /**
     * 删除文章
     *
     * @param ids id的list
     */
    public <T> int remove(String idName, List<String> ids, Class<T> tClass) {
        Query query = new Query();
        query.addCriteria(Criteria.where(idName).in(ids));
        mongoTemplate.remove(query, tClass);
        return 1;
    }

    /**
     * 查询单条数据
     *
     * @param id id
     * @return 结果
     */
    public <T> T findById(String id, Class<T> tClass) {
        return mongoTemplate.findById(id, tClass);
    }

    /**
     * 查询list数据
     * 根据 fieldName 字段的值 fieldValue 进行模糊查询
     *
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @param tClass 对应的数据库集合名字
     * @return 结果
     */
    public <T> List<T> find(String fieldName, String fieldValue, Class<T> tClass) {
        Query query = new Query();
        query.addCriteria(Criteria.where(fieldName)
                .regex(Pattern.compile("^.*" + fieldValue + ".*$", Pattern.CASE_INSENSITIVE)));
        return mongoTemplate.find(query, tClass);
    }

    /**
     * enterpriseCode 统一社会信用代码
     * statDate 数据统计时间
     * dataCode 上传数据项编码
     * responseCode 成功/失败
     */
    public <T> List<T> find3(String enterpriseCode, String statDate, String dataCode, Integer responseCode, Class<T> tClass) {

        Map<String, Object> map = new HashMap<>(4);
        if (!ObjectUtils.isEmpty(enterpriseCode)) {
            map.put("enterpriseCode", enterpriseCode);
        }
        if (!ObjectUtils.isEmpty(statDate)) {
            map.put("statDate", statDate);
        }
        if (!ObjectUtils.isEmpty(dataCode)) {
            map.put("dataCode", dataCode);
        }
        if (!ObjectUtils.isEmpty(responseCode)) {
            map.put("responseCode", responseCode);
        }

        int i = 0;
        Criteria criteria = null;
        for (String key : map.keySet()) {
            if (i == 0) {
                criteria = Criteria.where(key).is(map.get(key));
            } else {
                criteria.and(key).is(map.get(key));
            }
            i++;
        }
        Query query = Query.query(criteria);
        return mongoTemplate.find(query, tClass, "sbLog");
    }

    /**
     * 分页查询
     *
     * @param criteriaVO 查询条件
     * @param tClass 查询实体
     * @param collectionName 对应的数据库集合名字
     * @param <T> 泛型
     * @return 结果
     */
    public <T> List<T> paginQuery(Object criteriaVO, Class<T> tClass, String collectionName) {

        Query query = null;
        try {
            query = createQuery(criteriaVO);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        return mongoTemplate.find(query, tClass, collectionName);
    }

    /**
     * 总条数
     *
     * @param criteriaVO 查询条件
     * @param tClass 查询实体
     * @param collectionName 对应的数据库集合名字
     * @param <T> 泛型
     * @return 总条数
     */
    public <T> long count(Object criteriaVO, Class<T> tClass, String collectionName) {

        Query query = null;
        try {
            query = createQuery(criteriaVO);
            query.skip(0).limit(0);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        return mongoTemplate.count(query, tClass, collectionName);
    }

    /**
     *
     * @param criteriaVO 查询条件
     * @return Query
     * @throws IllegalAccessException 异常
     */
    private Query createQuery(Object criteriaVO) throws IllegalAccessException {

        Query query = new Query();

        Criteria criteria = null;
        Class<?> aClass = criteriaVO.getClass();
        Field[] fields = aClass.getDeclaredFields();

        long pageNum = 0L;
        int pageSize = 0;

        for (Field field : fields) {
            field.setAccessible(true);
            Like like = field.getAnnotation(Like.class);
            Ge ge = field.getAnnotation(Ge.class);
            Le le = field.getAnnotation(Le.class);
            PageSize pageSize1 = field.getAnnotation(PageSize.class);
            PageNum pageNum1 = field.getAnnotation(PageNum.class);
            com.ynkbny.annotate.Sort sort = field.getAnnotation(com.ynkbny.annotate.Sort.class);

            if (ObjectUtil.isEmpty(field.get(criteriaVO))) {
                continue;
            }

            if (ObjectUtil.isNull(criteria)) {
                if (ObjectUtil.isNotNull(like)) {
                    criteria = Criteria.where(field.getName())
                            .regex(Pattern.compile("^.*" + field.get(criteriaVO) + ".*$", Pattern.CASE_INSENSITIVE));
                } else if (ObjectUtil.isNotNull(ge)) {
                    criteria = Criteria.where(field.getName()).gte(field.get(criteriaVO));
                } else if (ObjectUtil.isNotNull(le)) {
                    criteria = Criteria.where(field.getName()).lte(field.get(criteriaVO));
                } else if (ObjectUtil.isNotNull(pageNum1)) {
                    pageNum = (long) field.get(criteriaVO);
                } else if (ObjectUtil.isNotNull(pageSize1)) {
                    pageSize = Integer.parseInt(String.valueOf(field.get(criteriaVO)));
                } else {
                    criteria = Criteria.where(field.getName()).is(field.get(criteriaVO));
                }
            } else {
                if (ObjectUtil.isNotNull(like)) {
                    criteria.and(field.getName())
                            .regex(Pattern.compile("^.*" + field.get(criteriaVO) + ".*$", Pattern.CASE_INSENSITIVE));
                } else if (ObjectUtil.isNotNull(ge)) {
                    criteria.and(field.getName()).gte(field.get(criteriaVO));
                } else if (ObjectUtil.isNotNull(le)) {
                    criteria.and(field.getName()).lte(field.get(criteriaVO));
                } else if (ObjectUtil.isNotNull(pageNum1)) {
                    pageNum = (long) field.get(criteriaVO);
                } else if (ObjectUtil.isNotNull(pageSize1)) {
                    pageSize = Integer.parseInt(String.valueOf(field.get(criteriaVO)));
                } else {
                    criteria.and(field.getName()).is(field.get(criteriaVO));
                }
            }
            query.with(Sort.by(Sort.Direction.DESC, "statDate"));
        }

        if (ObjectUtil.isNotNull(criteria)) {
            query.addCriteria(criteria);
        }

        query.skip((pageNum - 1) * pageSize).limit(pageSize);

        return query;
    }


    /**
     * 创建自定义倒序字段查询
     * @Author YY
     * @param criteriaVO 查询条件
     * @return Query
     * @throws IllegalAccessException 异常
     */
    private Query createQuery2(Object criteriaVO,List<String> fileList) throws IllegalAccessException {

        List<Sort.Order> orders = new ArrayList<>();
        fileList.forEach(n -> orders.add(new Sort.Order(Sort.Direction.DESC, n)));

        Query query = new Query();

        Criteria criteria = null;
        Class<?> aClass = criteriaVO.getClass();
        Field[] fields = aClass.getDeclaredFields();

        long pageNum = 0L;
        int pageSize = 0;

        for (Field field : fields) {
            field.setAccessible(true);
            Like like = field.getAnnotation(Like.class);
            Ge ge = field.getAnnotation(Ge.class);
            Le le = field.getAnnotation(Le.class);
            PageSize pageSize1 = field.getAnnotation(PageSize.class);
            PageNum pageNum1 = field.getAnnotation(PageNum.class);
            com.ynkbny.annotate.Sort sort = field.getAnnotation(com.ynkbny.annotate.Sort.class);

            if (ObjectUtil.isEmpty(field.get(criteriaVO))) {
                continue;
            }

            if (ObjectUtil.isNull(criteria)) {
                if (ObjectUtil.isNotNull(like)) {
                    criteria = Criteria.where(field.getName())
                            .regex(Pattern.compile("^.*" + field.get(criteriaVO) + ".*$", Pattern.CASE_INSENSITIVE));
                } else if (ObjectUtil.isNotNull(ge)) {
                    criteria = Criteria.where(field.getName()).gte(field.get(criteriaVO));
                } else if (ObjectUtil.isNotNull(le)) {
                    criteria = Criteria.where(field.getName()).lte(field.get(criteriaVO));
                } else if (ObjectUtil.isNotNull(pageNum1)) {
                    pageNum = (long) field.get(criteriaVO);
                } else if (ObjectUtil.isNotNull(pageSize1)) {
                    pageSize = Integer.parseInt(String.valueOf(field.get(criteriaVO)));
                } else {
                    criteria = Criteria.where(field.getName()).is(field.get(criteriaVO));
                }
            } else {
                if (ObjectUtil.isNotNull(like)) {
                    criteria.and(field.getName())
                            .regex(Pattern.compile("^.*" + field.get(criteriaVO) + ".*$", Pattern.CASE_INSENSITIVE));
                } else if (ObjectUtil.isNotNull(ge)) {
                    criteria.and(field.getName()).gte(field.get(criteriaVO));
                } else if (ObjectUtil.isNotNull(le)) {
                    criteria.and(field.getName()).lte(field.get(criteriaVO));
                } else if (ObjectUtil.isNotNull(pageNum1)) {
                    pageNum = (long) field.get(criteriaVO);
                } else if (ObjectUtil.isNotNull(pageSize1)) {
                    pageSize = Integer.parseInt(String.valueOf(field.get(criteriaVO)));
                } else {
                    criteria.and(field.getName()).is(field.get(criteriaVO));
                }
            }
            query.with(Sort.by(orders));
        }

        if (ObjectUtil.isNotNull(criteria)) {
            query.addCriteria(criteria);
        }

        query.skip((pageNum - 1) * pageSize).limit(pageSize);

        return query;
    }

    /**
     * 分页查询
     * @Author YY
     * @param criteriaVO 查询条件
     * @param tClass 查询实体
     * @param collectionName 对应的数据库集合名字
     * @param <T> 泛型
     * @return 结果
     */
    public <T> List<T> pageQuery(Object criteriaVO, Class<T> tClass, String collectionName,List<String> fileList) {

        Query query = null;
        try {
            query = createQuery2(criteriaVO,fileList);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        return mongoTemplate.find(query, tClass, collectionName);
    }

}
